//
// Copyright 2001-2004 Stottler Henke Associates, Inc.
// All Rights Reserved.
//////////////////////////////////////////////////////////////////////

package com.stottlerhenke.simbionic.engine.parser;

import java.util.List;
import java.util.ArrayList;

import com.stottlerhenke.simbionic.api.*;
import com.stottlerhenke.simbionic.engine.SB_SimInterface;
import com.stottlerhenke.simbionic.engine.SB_SingletonBook;
import com.stottlerhenke.simbionic.engine.file.SB_StreamReader;
import com.stottlerhenke.simbionic.common.SB_Logger;
import com.stottlerhenke.simbionic.common.SIM_Constants;

/**
 * Represents a single variable of type array.
 */
public class SB_VarArray extends SB_Variable
{
  public SB_VarArray() throws SB_Exception
  {
    _parameterValue = new SB_Param( new ArrayList() );
  }

  /**
   * Perform a shallow copy
   *
   * @param var
   */
  public SB_VarArray(SB_VarArray var) throws SB_Exception
  {
    _parameterValue.setArray( var.getSB_Param().getArray() );
  }

  /**
   * The constructor makes the internal _list point to list
   * @param list
   */
  public SB_VarArray(List list) throws SB_Exception
  {
	  _parameterValue = new SB_Param( list );
  }

  /**
   * Performs a deep copy (except of SB_VarData objects)
   *
   * @param var
   */
  private void Copy( SB_VarArray var)throws SB_Exception
  {
    _parameterValue.copy(var.getSB_Param());
  }


  /**
   *
   * performs a RECURSIVE deep copy of the given array
   */
  public void deepCopy( SB_VarArray var) throws SB_Exception
  {
  	_parameterValue.copyArray(var.getSB_Param());
  }
  
  /**
   * Array variables can be assigned to each other just like any other data type.
   * Assignment is by reference.  Thus, after the binding
   *	array2 = array1
   * both arrays point to the same array object.
   * Similarly, arrays as parameters use pass-by-reference semantics.
   * This is generally the desired behavior (as well as the most efficient behavior),
   * but if a copy is desired a predicate is provided for that purpose.
   *
   * However, this causes a problem with backtracking
   *
   * @return A deep copy of the current array
   */
  public SB_Variable Clone() throws SB_Exception
  {
    SB_VarArray returnValue = new SB_VarArray();
    returnValue.Copy(this);
    return returnValue;

  }

  public void setSB_Param(SB_Param newParam) throws SB_Exception
  {
      if(! SB_Config.USE_SB_PARAM_ARRAYS)
      {
          _parameterValue = newParam.cloneParam();
      }
      else
      {
          _parameterValue = new SB_Param( SB_SimInterface.ConvertObjectsToSB_Param( newParam.getArray( ) ) );
      }
  }
  
  public SB_VarType GetType()
  {
    return SB_VarType.kArray;
  }

  public static List GET_ARRAY(SB_Variable var2) throws SB_Exception
  {
    return ((SB_VarArray)var2).GetValue();
  }

  public List GetValue() throws SB_Exception
  {
    return _parameterValue.getArray();
  }

  /**
   * @param index
   * @return the element at the given position of the given array.
   */
 /* public SB_Variable get(SB_VarInteger index)
  {
    return get(index.GetValue());
  }
*/
  /**
   *
   * @param index
   * @return A SB_Variable wrapper around a copy of the SB_Param object indexed.
   */
  public SB_Variable GetArrayEntry(int index, SB_SingletonBook book) throws SB_Exception
  {
    SB_Param value = (SB_Param) _parameterValue.getArrayEntry(index);
    return SB_SimInterface.ConvertParamAuto( value, book );
  }

  public SB_Variable GetArrayEntry(SB_VarInteger index, SB_SingletonBook book) throws SB_Exception
  {
    return GetArrayEntry(index.GetValue(), book);
  }

  /**
   * Deletes the element at the end of the given array.  Returns the popped element. The array size will also be decremented by one.
   * @return
   */
  public SB_Variable pop(SB_SingletonBook book)
  throws SB_Exception
  {
    int nLastItem = _parameterValue.getArraySize() - 1;
    SB_Variable returnValue = GetArrayEntry( nLastItem, book);
    _parameterValue.arrayDelete(nLastItem);

    return returnValue;
  }

  /**
   * Sets the element at the given position of the given array to the given value.
   * @param index
   * @param value
   */
  public void ArraySet(SB_VarInteger index, SB_Variable value)
  throws SB_Exception
  {
    _parameterValue.arraySet(index.GetValue(), value.getSB_Param());
  }

  /**
   * Inserts the given element into the given array at the specified position.
   * All elements with index >= position before the insertion will have index = index+1 after the insertion.
   * The array size will also be incremented by one.
   * @param index
   * @param value
   */
  public void ArrayInsert(SB_VarInteger index, SB_Variable value)
  throws SB_Exception
  {
    _parameterValue.arrayInsert(index.GetValue(), value.getSB_Param());
  }

  /**
   * Specialty internal function
   *
   * Inserts the given element at the end of the given array.
   * The array size will also be incremented by one.
   * @param value
   */
  public void push(SB_Variable value) throws SB_Exception
  {
    _parameterValue.arrayAdd(value.getSB_Param());
  }

  /**
   * Deletes the element at the specified position from the array.
   * All elements with index  > position before the deletion will have index = index-1 after the deletion.
   * The array size will also be decremented by one.
   * @param index
   */
  public void ArrayDelete(SB_VarInteger index)
  throws SB_Exception
  {
    _parameterValue.arrayDelete(index.GetValue());
  }

  /**
   * When assigned, the two arrays will point to the same object
   *
   * @param var
   * @return
   */
  public SB_Variable opAssign(SB_VarArray var) throws SB_Exception
  {
    if (this != var)
    {
      _parameterValue.setArray(var.GetValue());
    }

    return this;
  }

  /**
   *
   * @return an array string representation {item1, item2, ..., itemn}
   */
  public String toString()
  {
  /*
    StringBuffer buff = new StringBuffer();

    int nCount = GetValue().size();
    for( int x = 0; x < nCount; x++ )
    {
      if( x == 0 )
        buff.append("{");
      else
        buff.append(", ");

      buff.append(  GetValue().get(x).toString() );

      if( x == (nCount - 1) )
        buff.append("}");
    }

    return buff.toString();*/

    return _parameterValue.toString();
  }


  /**
   *
   * Load the vector name, then the number of SB_Variables to load.
   * Set the list size to be that number, then (using a for loop) load each of the variables and add it to the array.
   * @param reader the stream reader to read the array from
   * @throws SB_Exception
   */
  public void load(SB_StreamReader reader,SB_SingletonBook book) 
		throws SB_Exception
  {
    int numberVariables = reader.readInt();

    for( int x = 0; x < numberVariables; x++ )
    {
      // read variable name
      reader.readPString();

      SB_Variable item = SB_Variable.readVariable(reader,book,true);
      _parameterValue.arrayAdd(item.getSB_Param());
    }
    
    if(SIM_Constants.DEBUG_INFO_ON)
        book.getLogger().log(".Loaded array.",SB_Logger.INIT);
  }

}
